Criminaliteit en Welvaart#
Student names: Chris Dukker, David Snoeks, Ryan Rodrigus, Jason Roes
Team number: D2
# Load image from link
url = 'https://ccv-secondant.nl/fileadmin/w/secondant_nl/platform/illustraties/Internationaal.jpg'
# Display image from URL with smaller size and subtitle
from IPython.display import Image, display
# Set the desired image width and height
width = 600
height = 300
# Set the subtitle text
#subtitle = "© CCV / Hans Sprangers"
# Create an Image instance with the URL
image = Image(url=url, width=width, height=height)
# Display the image and subtitle
display(image)
#print(subtitle)

Introduction#
Europa is, over het algemeen genomen, welvarend. Meerdere van de sterkste economieën op aarde bevinden zich op dit continent, en de EU kan zich in economische termen meten aan andere grootmachten. Deze welvaart is alleen niet gelijkmatig verdeeld. Sommige landen zijn welvarender dan andere, maar ook binnen de landen bestaat er economische ongelijkheid doordat de welvaart verschillend is verdeeld. Ook zijn er verscillen in de criminaliteit. Landen hebben te kampen met verschillende hoeveelheden misdaad, en niet ieder land heeft last van dezelfde soorten criminaliteit. De vraag waar wij ons in dit datastory mee bezig houden is: is er een verband te vinden in (de verdeling van) welvaart van een land, en de hoeveelheid illegale activiteit in dit land?
Met deze data story onderzoeken wij of welvaartsongelijkheid en het gemiddelde inkomen per persoon invloed hebben op de hoeveelheid gepleegde misdaden, en of deze variabelen een sterkere correlatie vertonen met bepaalde categorieën misdaad zoals moord, verkrachting, diefstal en fraude. Dit doen we met behulp van gegevens van World Bank Group over de GINI-coëfficient (een maatstaf voor inkomens- of vermogenongelijkheid) en economische statistieken en groei dataset van World Bank Open Data en de misdaadstatistieken dataset van Eurostat.
Hieronder kan geschrapt worden?
Volgens De Courson & Nettle (2021) is voor mensen met een laag inkomen en kapitaal de criminaliteit de beste manier om hun kwaliteit van leven te verbeteren. Hoewel er het risico is om gepakt te worden, is de mogelijke winst bij succes dit risico waard. Vanwege het kleine toekomstperspectief is misdaad voor deze bevolkingsgroep de beste manier om hun leven te verbeteren. Volgens ditzelfde onderzoek leidt een grote ongelijkheid tot meer criminaliteit, terwijl een eerlijkere verdeling van welvaart positieve effecten heeft en de mogelijke voordelen van misdaad verkleint.
The Second Argument of Your First Perspective#
bla bla
Show code cell source
import plotly.graph_objects as go
import pandas as pd
Figure 3:
blabla
Your Second Perspective#
Bla bla, Criminaliteit en welvaart (ongelijkheid) hebben geen sterk verband/ er zijn belangrijke factoren, want de argumenten hier onder.
The First Argument of Your Second Perspective#
Hoewel je misschien zou denken dat er in armere landen meer misdaden gebeuren, voornamelijk diefstal, wat het grootste deel van het aantal gerapporteerde misdaden uitmaakt, is dit juist niet het geval. Toen we onze dataset analyseerden vonden we juist dat over het algemeen hoe rijker een land is, hoe groter het totaal aantal gerapporteerde misdaden is.
Show code cell source
import pandas as pd
import plotly.express as px
import statsmodels
import plotly.io as pio
pio.renderers.default = 'notebook'
# Load and process data (same as before)
bank1_df = pd.read_csv("world_bank_definitive.csv")
crime_df = pd.read_csv("europe_crime_definitive_per_100k.csv")
bank_df = bank1_df[bank1_df['Indicator Name'] == "GDP per capita, PPP (constant 2021 international $)"]
bank_df = bank_df.rename(columns={"Value": "GDP per capita, PPP (constant 2021 international $)"})
crime_columns = [col for col in crime_df.columns if col not in ["Country Name", "Year", "geo"]]
crime_df["Total Crime Rate per 100k"] = crime_df[crime_columns].sum(axis=1)
merged_df = pd.merge(
crime_df[["Country Name", "Year", "Total Crime Rate per 100k"]],
bank_df[["Country Name", "Year", "GDP per capita, PPP (constant 2021 international $)"]],
on=["Country Name", "Year"]
)
# Create scatter plot with trendline
fig = px.scatter(
merged_df,
x="GDP per capita, PPP (constant 2021 international $)",
y="Total Crime Rate per 100k",
hover_name="Country Name",
hover_data={"Year": True},
trendline="ols", # Ordinary Least Squares regression line
title="GDP per Capita vs. Total Crime Rate per 100k"
)
fig.update_layout(
xaxis_title="GDP per capita, PPP (constant 2021 international $)",
yaxis_title="Total Crime Rate per 100k"
)
fig.show()
Het gemiddelde vermogen per persoon in een land in dollars tegen over het totaal aantal misdaden per land. Elk land is voor elk jaar dat het voorkomt in onze dataset weergegeven. Hover om de exacte waarden, het land en het jaar te zien van het datapunt
Het zou mogelijk kunnen zijn dat rijkere landen meer geldmiddelen hebben om criminelen te pakken en om te besteden aan handhaving/politie en dat daardoor het aantal geregistreerde misdaden hoger is, terwijl er niet perse meer misdaden gebeuren. Een andere mogelijke verklaring is dat criminelen meer toegang hebben tot middelen om misdaden te plegen en daardoor eerder geneigd te zijn om misdaden te plegen.
The Second Argument of Your Second Perspective#
Meer ongelijkheid lijdt tot minder gerapporteerde misdaden. Zoals je kan zien in de grafiek hieronder is in landen met een lagere GINI (dus meer ongelijkheid), een lager aantal misdaden.
Show code cell source
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import plotly.io as pio
import pycountry
pio.renderers.default = 'notebook'
# === Load GINI Data ===
gini_df = pd.read_csv("gini_definitive.csv")
gini_df['Year'] = gini_df['Year'].astype(int)
# === Load Theft Data ===
theft_df = pd.read_csv("europe_crime_definitive_per_100k.csv")
theft_df.rename(columns={'geo': 'Country Code'}, inplace=True)
theft_columns = [col for col in theft_df.columns if col not in ["Country Name", "Year", "Country Code"]]
theft_df["Total Crime Rate per 100k"] = theft_df[crime_columns].sum(axis=1)
# Convert ISO-2 to ISO-3
def convert_iso2_to_iso3(code):
try:
return pycountry.countries.get(alpha_2=code).alpha_3
except:
return None
theft_df['Country Code'] = theft_df['Country Code'].apply(convert_iso2_to_iso3)
# Manual fixes for special regions/countries
manual_fix = {
'England and Wales': 'GBR',
'Northern Ireland (UK) (NUTS 2021)': 'GBR',
'Scotland (NUTS 2021)': 'GBR',
'Greece': 'GRC',
'Kosovo*': 'XKX'
}
theft_df['Year'] = theft_df['Year'].astype(int)
theft_df['Total Crime Rate per 100k'] = pd.to_numeric(theft_df['Total Crime Rate per 100k'], errors='coerce').fillna(0)
# === Years intersection and max year 2022 ===
years = sorted(list(set(gini_df['Year']).intersection(set(theft_df['Year']))))
years = [year for year in years if year <= 2022]
# Create subplot
fig = make_subplots(
rows=1, cols=2,
specs=[[{'type': 'choropleth'}, {'type': 'choropleth'}]],
subplot_titles=('GINI Index', 'Crimes per 100k')
)
# Define color scales
gini_min, gini_max = gini_df['Value'].min(), gini_df['Value'].max()
theft_min, theft_max = theft_df['Total Crime Rate per 100k'].min(), theft_df['Total Crime Rate per 100k'].max()
# Add base traces (Year = first year)
fig.add_trace(
go.Choropleth(
locations=gini_df[gini_df['Year'] == years[0]]['Country Code'],
z=gini_df[gini_df['Year'] == years[0]]['Value'],
text=gini_df[gini_df['Year'] == years[0]]['Country Name'],
colorscale='Viridis',
zmin=gini_min,
zmax=gini_max,
colorbar=dict(title='GINI', x=0.45) # position colorbar left
),
row=1, col=1
)
fig.add_trace(
go.Choropleth(
locations=theft_df[theft_df['Year'] == years[0]]['Country Code'],
z=theft_df[theft_df['Year'] == years[0]]['Total Crime Rate per 100k'],
text=theft_df[theft_df['Year'] == years[0]]['Country Name'],
colorscale='Reds',
zmin=theft_min,
zmax=theft_max,
colorbar=dict(title='Total Crime Rate per 100k', x=1.0) # position colorbar right
),
row=1, col=2
)
# Animation frames
frames = []
for year in years:
frame = go.Frame(
data=[
go.Choropleth(
locations=gini_df[gini_df['Year'] == year]['Country Code'],
z=gini_df[gini_df['Year'] == year]['Value'],
text=gini_df[gini_df['Year'] == year]['Country Name']
),
go.Choropleth(
locations=theft_df[theft_df['Year'] == year]['Country Code'],
z=theft_df[theft_df['Year'] == year]['Total Crime Rate per 100k'],
text=theft_df[theft_df['Year'] == year]['Country Name']
)
],
name=str(year)
)
frames.append(frame)
# Update layout
fig.update_layout(
title_text='GINI Index and Total Crime per 100k in Europe per Year',
title_x=0.5,
geo=dict(
showframe=False,
showcoastlines=True,
lataxis_range=[30, 72],
lonaxis_range=[-25, 45],
projection_type='natural earth'
),
geo2=dict( # for the 2nd map
showframe=False,
showcoastlines=True,
lataxis_range=[30, 72],
lonaxis_range=[-25, 45],
projection_type='natural earth'
),
sliders=[{
"steps": [{
"args": [[str(year)], {"frame": {"duration": 500, "redraw": True}, "mode": "immediate"}],
"label": str(year),
"method": "animate"
} for year in years],
"transition": {"duration": 300},
"x": 0.1,
"len": 0.8
}],
updatemenus=[{
"buttons": [{
"args": [None, {"frame": {"duration": 500, "redraw": True}, "fromcurrent": True}],
"label": "Play",
"method": "animate"
}, {
"args": [[None], {"frame": {"duration": 0}, "mode": "immediate"}],
"label": "Pause",
"method": "animate"
}],
"direction": "left",
"pad": {"r": 10, "t": 70},
"showactive": False,
"type": "buttons",
"x": 0.1,
"xanchor": "right",
"y": 0,
"yanchor": "top"
}]
)
fig.frames = frames
fig.show()
De kaart van Europa met GINI index per land per jaar en het totaal aantal misdaden. Hover over een land om de naam en waarde te zien. Scroll om voor verschillende jaren te zien
ddd
Show code cell source
import pandas as pd
import plotly.express as px
import random
Figure 6: blabla
Reflection#
d
Work Distribution#
Jason richtte zich op het preprocessen van de datasets. Hierna focusde hij zich vooral op het coordineren van de samenwerking en begeleidende tekst voor het datastory.
References#
De Courson, B., Nettle, D. Why do inequality and deprivation produce high crime and low trust?. Sci Rep 11, 1937 (2021). https://doi.org/10.1038/s41598-020-80897-8